package com.lanp.gencode.utils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.core.ReflectUtils;

import java.beans.PropertyDescriptor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author jiangpeng
 * Created with IntelliJ IDEA.
 * Description:  bean常用工具
 * Date: 2022-06-08 17:11:18
 */
@Slf4j
public class SiGoBeanUtil {
    private static final ConcurrentHashMap<Class, CopyOptions> cacheFiledMap = new ConcurrentHashMap();

    /**
     * 下划线转驼峰
     *
     * @param clazz
     * @return
     */
    public static CopyOptions getClassCopyOption(Class clazz) {
        CopyOptions copyOptions = cacheFiledMap.get(clazz);
        if (copyOptions != null) {
            return copyOptions;
        }
        //获取类的字段
        PropertyDescriptor[] beanProperties = ReflectUtils.getBeanProperties(clazz);
        Map<String, String> filedNameMap = new HashMap<>();
        for (PropertyDescriptor beanProperty : beanProperties) {
            String name = beanProperty.getName();
            String name_ = StrUtil.toCamelCase(name);
            if (!filedNameMap.containsKey(name)) {
                filedNameMap.put(name, name_);
            }
        }
        copyOptions = CopyOptions.create();
        cacheFiledMap.put(clazz, copyOptions);
        CopyOptions copyOptionsRes = copyOptions.setFieldMapping(filedNameMap);
        return copyOptionsRes;
    }
    /**
     * 驼峰转下划线
     *
     * @param clazz
     * @return
     */
    public static CopyOptions getClassCopyOptionLineCase(Class clazz) {
        CopyOptions copyOptions = cacheFiledMap.get(clazz);
        if (copyOptions != null) {
            return copyOptions;
        }
        //获取类的字段
        PropertyDescriptor[] beanProperties = ReflectUtils.getBeanProperties(clazz);
        Map<String, String> filedNameMap = new HashMap<>();
        for (PropertyDescriptor beanProperty : beanProperties) {
            String name = beanProperty.getName();
            String name_ = StrUtil.toUnderlineCase(name);
            if (!filedNameMap.containsKey(name)) {
                filedNameMap.put(name, name_);
            }
        }
        copyOptions = CopyOptions.create();
        cacheFiledMap.put(clazz, copyOptions);
        CopyOptions copyOptionsRes = copyOptions.setFieldMapping(filedNameMap);
        return copyOptionsRes;
    }

    /**
     * 下划线属性复制到驼峰属性
     *
     * @param source
     * @param target
     */
    public static void _copyProperties(Object source, Object target) {
        CopyOptions classCopyOption = getClassCopyOption(source.getClass());
        BeanUtil.copyProperties(source, target, classCopyOption);
    }

    /**
     * 驼峰属性复制到下划线属性
     *
     * @param source
     * @param target
     */
    public static void copyProperties_(Object source, Object target) {
        CopyOptions classCopyOption = getClassCopyOptionLineCase(source.getClass());
        BeanUtil.copyProperties(source, target, classCopyOption);
    }

    /**
     * copy数组
     *
     * @param sourceList
     * @param <T>
     * @return
     */
    public static <T, S> List<T> copyList(List<S> sourceList, Class<T> clazz) {
        List<T> ress = new ArrayList<>(sourceList.size());
        for (Object o : sourceList) {
            T to = null;
            try {
                to = clazz.newInstance();
            } catch (InstantiationException e) {
                log.error("sigo copyList 异常",e);
            } catch (IllegalAccessException e) {
                log.error("sigo copyList 异常",e);
            }
            BeanUtil.copyProperties(o, to);
            ress.add(to);
        }
        return ress;
    }/**
     * copy数组
     *
     * @param sourceList
     * @param <T>
     * @return
     */
    public static <T, S> List<T> copyList_(List<S> sourceList, Class<T> clazz) {
        List<T> ress = new ArrayList<>();
        for (Object o : sourceList) {
            T to = null;
            try {
                to = clazz.newInstance();
            } catch (InstantiationException e) {
                log.error("sigo copyList_ 异常",e);
            } catch (IllegalAccessException e) {
                log.error("sigo copyList_ 异常",e);
            }
            copyProperties_(o, to);
            ress.add(to);
        }
        return ress;
    }
    /**
     * copy数组
     *
     * @param sourceList
     * @param <T>
     * @return
     */
    public static <T, S> List<T> _copyList(List<S> sourceList, Class<T> clazz) {
        List<T> ress = new ArrayList<>();
        for (Object o : sourceList) {
            T to = null;
            try {
                to = clazz.newInstance();
            } catch (InstantiationException e) {
                log.error("sigo _copyList 异常",e);
            } catch (IllegalAccessException e) {
                log.error("sigo _copyList 异常",e);
            }
            _copyProperties(o, to);
            ress.add(to);
        }
        return ress;
    }
    /**
     * copy bean
     *
     * @param source
     * @param <T>
     * @return
     */
    public static <T, S> T _copyToBean(S source, Class<T> clazz) {
        T to = null;
        try {
            to = clazz.newInstance();
        } catch (InstantiationException e) {
            log.error("sigo _copyToBean 异常",e);
        } catch (IllegalAccessException e) {
            log.error("sigo _copyToBean 异常",e);
        }
        SiGoBeanUtil._copyProperties(source, to);
        return to;
    }/**
     * copy bean
     *
     * @param source
     * @param <T>
     * @return
     */
    public static <T, S> T copyToBean_(S source, Class<T> clazz) {
        T to = null;
        try {
            to = clazz.newInstance();
        } catch (InstantiationException e) {
            log.error("sigo copyToBean_ 异常",e);
        } catch (IllegalAccessException e) {
            log.error("sigo copyToBean_ 异常",e);
        }
        SiGoBeanUtil.copyProperties_(source, to);
        return to;
    }
    /**
     * 数组转map,一个key对应一个值，为了防止重复key，写的，可以随机取一个值做val
     * @param list
     * @param keyMapper
     * @param <T> 实体类
     * @param <K> 主键
     * @return
     */
    public static <T, K> Map<K, T> toDistinctMap(List<T> list, Function<? super T, ? extends K> keyMapper) {
        Map<K, T> resm = new HashMap<>();
        list.forEach(val -> {
            K apply = keyMapper.apply(val);
            resm.put(apply, val);
        });
        return resm;
    }

    public static <T, K, U> Map<K, T> toMap(List<T> list, Function<? super T, ? extends K> keyMapper) {
        return list.stream().collect(Collectors.toMap(keyMapper, Function.identity()));
    }

    public static <T, K, U> Map<K, List<T>> toListMap(List<T> list, Function<? super T, ? extends K> keyMapper) {
        return list.stream().collect(Collectors.groupingBy(keyMapper));
    }





    /**
     * toString
     * @param obj
     * @return
     */
    public static String toString(Object obj){
        return obj == null ? null : obj.toString();
    }

}
